/*
 *Copyright 2021-2023 NERCIS
 *
 *Licensed under the Apache License, Version 2.0 (the "License");
 *you may not use this file except in compliance with the License.
 *You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 *Unless required by applicable law or agreed to in writing, software
 *distributed under the License is distributed on an "AS IS" BASIS,
 *WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *See the License for the specific language governing permissions and
 *limitations under the License.
 */

package cn.ac.nercis.pes.service.utils;

import cn.ac.nercis.pes.common.constant.knowledge.AssetClassification;
import cn.ac.nercis.pes.model.dto.evaluation.asset.*;
import cn.ac.nercis.pes.model.standard.SystemProcessSDTO;
import cn.ac.nercis.pes.model.standard.analyze.*;
import cn.ac.nercis.pes.model.standard.asset.AssetSDTO;
import cn.ac.nercis.pes.model.standard.evaluation.EvaluationRecordSDTO;
import cn.ac.nercis.pes.model.standard.planning.EvaluationDescSDTO;
import cn.ac.nercis.pes.model.standard.planning.EvaluationMethodSDTO;
import cn.ac.nercis.pes.model.standard.prepare.EvaluationContentSDTO;
import cn.ac.nercis.pes.model.standard.prepare.EvaluationProcessSDTO;
import cn.ac.nercis.pes.model.standard.report.EvaluationReportSDTO;
import cn.ac.nercis.pes.repository.mapper.standard.SystemImportMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;

/**
 * 自定义去重辅助类
 * @author zpy
 * @version 1.0.0
 */
@Slf4j
public final class DistinctUtils {
    private DistinctUtils(){}

    public static Predicate<SystemProcessSDTO> customSystemProcessDistinct(){
        final Map<String, SystemProcessSDTO> map = new ConcurrentHashMap<>();
        return data-> Objects.isNull(map.put(StringUtils.join(data.getSystemId(),data.getState(),data.getName()),data));
    }

    public static Predicate<EvaluationProcessSDTO> customEvaluationProcessDistinct(){
        final Map<String, EvaluationProcessSDTO> map = new ConcurrentHashMap<>();
        return data-> Objects.isNull(map.put(StringUtils.join(data.getSystemId(),data.getName()),data));
    }

    public static Predicate<EvaluationContentSDTO> customEvaluationContentDistinct(){
        final Map<String, EvaluationContentSDTO> map = new ConcurrentHashMap<>();
        return data-> Objects.isNull(map.put(StringUtils.join(data.getSystemId(),data.getNode()),data));
    }

    public static Predicate<EvaluationDescSDTO> customEvaluationDescDistinct(){
        final Map<String, EvaluationDescSDTO> map = new ConcurrentHashMap<>();
        return data-> Objects.isNull(map.put(StringUtils.join(data.getSystemId(),data.getAssetId(),data.getLayerTargetId()),data));
    }

    public static Predicate<EvaluationMethodSDTO> customEvaluationMethodDistinct(){
        final Map<String, EvaluationMethodSDTO> map = new ConcurrentHashMap<>();
        return data-> Objects.isNull(map.put(StringUtils.join(data.getSystemId(),data.getAssetId(),data.getUnitTargetId()),data));
    }

    public static Predicate<EvaluationRecordSDTO> customEvaluationRecordDistinct(){
        final Map<String, EvaluationRecordSDTO> map = new ConcurrentHashMap<>();
        return data-> Objects.isNull(map.put(StringUtils.join(data.getSystemId(),data.getAssetEvaMethodId()),data));
    }

    public static Predicate<UnitEvaluationSDTO> customUnitEvaluationDistinct(){
        final Map<String, UnitEvaluationSDTO> map = new ConcurrentHashMap<>();
        return data-> Objects.isNull(map.put(StringUtils.join(data.getSystemId(),data.getUnitTargetId()),data));
    }

    public static Predicate<LayerEvaluationSDTO> customLayerEvaluationDistinct(){
        final Map<String, LayerEvaluationSDTO> map = new ConcurrentHashMap<>();
        return data-> Objects.isNull(map.put(StringUtils.join(data.getSystemId(),data.getLayerTargetId()),data));
    }

    public static Predicate<OverallEvaluationSDTO> customOverallEvaluationDistinct(){
        final Map<String, OverallEvaluationSDTO> map = new ConcurrentHashMap<>();
        return data-> Objects.isNull(map.put(StringUtils.join(data.getSystemId(),data.getLayerTargetId()),data));
    }

    public static Predicate<ResultCorrectionSDTO> customResultCorrectionDistinct(){
        final Map<String, ResultCorrectionSDTO> map = new ConcurrentHashMap<>();
        return data-> Objects.isNull(map.put(StringUtils.join(data.getSystemId(),data.getUnitTargetId()),data));
    }

    public static Predicate<UnitRiskAnalysisSDTO> customUnitRiskAnalysisDistinct(){
        final Map<String, UnitRiskAnalysisSDTO> map = new ConcurrentHashMap<>();
        return data-> Objects.isNull(map.put(StringUtils.join(data.getSystemId(),data.getUnitTargetId()),data));
    }

    public static Predicate<EvaluationReportSDTO> customEvaluationReportDistinct(){
        final Map<String, EvaluationReportSDTO> map = new ConcurrentHashMap<>();
        return data-> Objects.isNull(map.put(StringUtils.join(data.getSystemId(),data.getReportType()),data));
    }

    public static Predicate<AssetSDTO> customAssetDistinct(){
        final Map<String, AssetSDTO> map = new ConcurrentHashMap<>();
        return data-> Objects.isNull(map.put(getAssetKey(data),data));
    }

    private static String getAssetKey(AssetSDTO asset){
        AssetClassification classification = AssetClassification.fromId(asset.getClassId());
        return switch (classification) {
            case PHY_ENV -> findAssetKeyByPhyEnv(asset, SystemImportMapper.INSTANCE.toPhyEnvDTO(asset));
            case PHY_SECURITY -> findAssetKeyByPhySecurity(asset,SystemImportMapper.INSTANCE.toPhySecurity(asset));
            case PWD_PRODUCT -> findAssetKeyByPwdProduct(asset,SystemImportMapper.INSTANCE.toPwdProduct(asset));
            case SERVER_STORAGE ->
                    findAssetKeyByServerStorage(asset,SystemImportMapper.INSTANCE.toServerStorage(asset));
            case NETWORK_SECURITY ->
                    findAssetKeyByNetworkSecurity(asset,SystemImportMapper.INSTANCE.toNetworkSecurity(asset));
            case DATABASE -> findAssetKeyByDatabase(asset,SystemImportMapper.INSTANCE.toDatabase(asset));
            case KEY_BUSINESS -> findAssetKeyByKeyBusiness(asset,SystemImportMapper.INSTANCE.toKeyBusiness(asset));
            case SUB_BUSINESS -> findAssetKeyBySubBusiness(asset,SystemImportMapper.INSTANCE.toSubBusiness(asset));
            case KEY_DATA -> findAssetKeyByKeyData(asset,SystemImportMapper.INSTANCE.toKeyData(asset));
            default -> asset.getName();
        };
    }

    private static String findAssetKeyByPhyEnv(AssetSDTO asset, PhyEnvDTO data){
        return StringUtils.join(asset.getSystemId(),asset.getClassId(),data.getName(),data.getLocation());
    }

    private static String findAssetKeyByPhySecurity(AssetSDTO asset, PhySecurityDTO data){
        return StringUtils.join(asset.getSystemId(),asset.getClassId(),data.getName(),data.getLocation());
    }

    private static String findAssetKeyByPwdProduct(AssetSDTO asset, PwdProductDTO data){
        return StringUtils.join(asset.getSystemId(),asset.getClassId(),data.getName(),data.getModel());
    }
    private static String findAssetKeyByServerStorage(AssetSDTO asset, ServerStorageDTO data){
        return StringUtils.join(asset.getSystemId(),asset.getClassId(),data.getName(),data.getVendor(),data.getModel());
    }
    private static String findAssetKeyByNetworkSecurity(AssetSDTO asset, NetworkSecurityDTO data){
        return StringUtils.join(asset.getSystemId(),asset.getClassId(),data.getName(),data.getVendor(),data.getModel());
    }
    private static String findAssetKeyByDatabase(AssetSDTO asset,DatabaseDTO data){
        return StringUtils.join(asset.getSystemId(),asset.getClassId(),data.getName(),data.getLocation());
    }
    private static String findAssetKeyByKeyBusiness(AssetSDTO asset,KeyBusinessDTO data){
        return StringUtils.join(asset.getSystemId(),asset.getClassId(),data.getName(),data.getLocation());
    }
    private static String findAssetKeyBySubBusiness(AssetSDTO asset,SubBusinessDTO data){
        return StringUtils.join(asset.getSystemId(),asset.getClassId(),data.getName(),data.getOwnedApp());
    }
    private static String findAssetKeyByKeyData(AssetSDTO asset,KeyDataDTO data){
        return StringUtils.join(asset.getSystemId(),asset.getClassId(),data.getData(),data.getOwnedApp(),data.getLocation());
    }
}
